<?php
/**
 * 作者：dbkuaizi
 * 博客：www.dbkuaizi.com
 * 时间：2021-06-14
 * 版本：1.0
 * 说明：PHP 数据字典生成脚本，支持 MySQL5.0+ PHP5.3+ ,需要开启 MySQLi 扩展
 */

// 如果没有配置数据库 则运行时手动输入

// 设置 MySQL地址
// $config['host']   = 'localhost';

// 设置 MySQL 用户名
// $config['username'] = 'root';

// 设置 MySQL 密码
// $config['password'] = '';

// 设置端口
// $config['port'] = 3306;


// 设置报错等级 如果数据库连接出错 提示而不是报错
ini_set('display_errors',0);

// 防止终端乱码,如果是windows 就设置终端字符集
if(strtoupper(substr(PHP_OS,0,3)) === 'WIN' ) exec("CHCP 65001");

// 如果没有设置config 就输入
if(!isset($config))
{
    output('===== 配置数据库 =====');
    $config['host'] = input('[1/5] MySQL 地址','localhost');
    $config['username'] = input('[2/5] MySQL 用户');
    $config['password'] = input('[3/5] MySQL 密码');
    $config['port'] = input('[4/5] MySQL 端口','3306');
    $config['exp_db'] = input('[5/5] 选择库','');
}
// 如果没有设置端口 则默认 3306
if (empty($config['port'])) $config['port'] = 3306; 
$connect = mysqli_connect($config['host'],$config['username'],$config['password'],'information_schema', $config['port']);
// 如果链接失败
if(!$connect){
    output("MySQL Connect Error");
    exit;
}

// 如果没有指定数据库
output('===== 请选择数据库 =====');

if(empty($config['exp_db'])){
    $result = $connect->query("SELECT SCHEMA_NAME FROM SCHEMATA");
   
    // 获取都有哪些数据库
    foreach($result->fetch_all(MYSQLI_ASSOC) as $database_key => $database_val) {
        $database_list[$database_key] = $database_val['SCHEMA_NAME'];
        fwrite(STDOUT,"[$database_key] => {$database_val['SCHEMA_NAME']}" . PHP_EOL) ;   
    }
    
    $db_key = input('选择要到导出的库，输入序号');
    
    if(!isset($database_list[$db_key])) {
        die('输入的序号不存在');
    }
    
    $config['exp_db'] = $database_list[$db_key];
}

// 选择导出文件路径
$export_name = input('选择导出文件名',$config['exp_db'] . date('ymd') .'.md');
$export_path = __DIR__ . DIRECTORY_SEPARATOR .$export_name;

// 获取表
output('===== 正在获取表结构 =====');
$result = $connect->query("SELECT TABLE_NAME,TABLE_TYPE,ENGINE,TABLE_COMMENT FROM `TABLES` WHERE TABLE_SCHEMA = '{$config['exp_db']}'");
$table_arr = $result->fetch_all(MYSQLI_ASSOC);

// 获取列,按照表名和列排序
$result = $connect->query("SELECT * FROM `COLUMNS` WHERE TABLE_SCHEMA = '{$config['exp_db']}' ORDER BY TABLE_NAME,ORDINAL_POSITION");
$col_arr = $result->fetch_all(MYSQLI_ASSOC);

 
foreach ($col_arr as $col_key => $col_val) {
    
    foreach($table_arr as $tab_key => $tab_val)
    {

        if($tab_val['TABLE_NAME'] == $col_val['TABLE_NAME']) {
            $col_val['COLUMN_COMMENT'] = str_replace(PHP_EOL,'<br/>',$col_val['COLUMN_COMMENT']);
            $table_arr[$tab_key]['col_arr'][] = $col_val;
        }

    }

}


output('===== 正在生成数据字典 =====');
$table_info = Array();
$table_info['type'] = Array('BASE TABLE' => '普通表','VIEW' =>"视图表",'SYSTEM VIEW' => '系统表');
$table_info['db_name'] = $config['exp_db'];
$table_info['path'] = $export_path;

// 获取SQL 版本
$table_info['version'] = $connect->query("SELECT VERSION() as version;")->fetch_array(MYSQLI_ASSOC)['version'];

$connect->close();
// 生成md
generate_md($table_arr, $table_info);
output('===== Export OK =====');

// ===========| 函数部分 |===========

// 生成md
function generate_md($table_arr, $table_info)
{
    $export_content = "# {$table_info['db_name']} 数据字典". PHP_EOL;
    $export_content .= '**数据库版本：** '. $table_info['version'] . PHP_EOL;
    $export_content .= '**导出时间：** '. DATE('Y-m-d H:i:s') . PHP_EOL;
    $export_content .= '**表数量：** '. COUNT($table_arr) . PHP_EOL . PHP_EOL;

    $table_type = $table_info['type'];
    foreach ($table_arr as $table_key => $table_item) {
        // 写入表信息
        $export_content .= "## {$table_item['TABLE_NAME']}" .PHP_EOL;
        if($table_item['TABLE_TYPE']) $export_content .= "**表类型：** {$table_type[$table_item['TABLE_TYPE']]} ".PHP_EOL;
        if($table_item['ENGINE']) $export_content .= "**表引擎：** {$table_item['ENGINE']}  ".PHP_EOL;
        if($table_item['TABLE_COMMENT']) $export_content .= "> **表备注：** {$table_item['TABLE_COMMENT']}  ".PHP_EOL;
        $export_content .= PHP_EOL;
    
        $export_content .= '|序号|字段名|字段类型|是否为空|默认值|其他|备注|'.PHP_EOL;
        $export_content .= '|:--:| ---- | ---- | ---- | ---- | ---- | ---- |'.PHP_EOL;

        // 写入列信息
        foreach($table_item['col_arr'] as $col_key => $col_val) {
            $col_index = $col_key + 1;
            $export_content .="| {$col_index} | {$col_val['COLUMN_NAME']} | {$col_val['COLUMN_TYPE']} | {$col_val['IS_NULLABLE']} | {$col_val['COLUMN_DEFAULT']} | {$col_val['EXTRA']} | {$col_val['COLUMN_COMMENT']} |";
            $export_content .= PHP_EOL;
        }
    
    }

    // 导出文件
    file_put_contents($table_info['path'],$export_content);
}


// 标准输入
function input($str, $default = false) {
    $input = false;

    // 如果有默认值
    if($default !== FALSE) {
        $str .= ", 默认 \"$default\"";
    }
    $str .= ': ';
    
    do {
        fwrite(STDOUT, $str);
        $input = trim(fgets(STDIN));
        // 如果没有默认值 且没有输入 
    } while (($default === false) && ($input == ''));

    // 如果有设置默认值，并且输入值为空 就使用默认值
    if($default !== false && $input == ''){
        $input = $default;
    }

    return $input;
}

// 标准输出
function output($str) {
    fwrite(STDOUT,$str . PHP_EOL);
}
